﻿using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace KeyCodeExchange
{
    [Command(PackageIds.MyCommand)]
    internal sealed class MyCommand : BaseCommand<MyCommand>
    {
        private static (char, char)[] keys =
            {
                ('`', 'ё'), ('~', 'Ё'), ('q', 'й'), ('w', 'ц')
                , ('e', 'у'), ('r', 'к'), ('t', 'е'), ('y', 'н')
                , ('u', 'г'), ('i', 'ш'), ('o', 'щ'), ('p', 'з')
                , ('[', 'х'), ('{', 'Х'), (']', 'ъ'), ('}', 'Ъ')
                , ('a', 'ф'), ('s', 'ы'), ('d', 'в'), ('f', 'а')
                , ('g', 'п'), ('h', 'р'), ('j', 'о'), ('k', 'л')
                , ('l', 'д'), (';', 'ж'), (':', 'Ж'), ('\'', 'э')
                , ('"', 'Э'), ('z', 'я'), ('x', 'ч'), ('c', 'с')
                , ('v', 'м'), ('b', 'и'), ('n', 'т'), ('m', 'ь')
                , ('.', 'ю'), ('>', 'Ю'), (',', 'б'), ('<', 'Б')
            };


        protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)
        {
            await Package.JoinableTaskFactory.SwitchToMainThreadAsync();

            var docView = await VS.Documents.GetActiveDocumentViewAsync();
            if (docView?.TextView == null) return;

            var selection = docView.TextView.Selection;
            if (selection == null)
            {
                await VS.MessageBox.ShowWarningAsync("KeyCodeExchange", "Необходимо выделить фрагмент");
                return;
            }

            try
            {
                var cyrDict = keys.ToDictionary(t => t.Item2, t => t.Item1);
                var latDict = keys.ToDictionary(t => t.Item1, t => t.Item2);

                selection.SelectedSpans
                    .ToList()
                    .ForEach(s =>
                    {
                        var textToTranslate = docView.TextView.TextSnapshot?.GetText(s.Span);
                        if (string.IsNullOrEmpty(textToTranslate))
                            throw new Exception("Необходимо выделить фрагмент");

                        if (Regex.IsMatch(textToTranslate, @"\p{IsCyrillic}"))
                        {
                            // at least one cyrrilc character exist
                            textToTranslate = Translate(textToTranslate, cyrDict);
                        }
                        else
                        {
                            textToTranslate = Translate(textToTranslate, latDict);
                        }

                        if (docView.TextBuffer.CheckEditAccess())
                        {
                            docView.TextBuffer.Replace(s.Span, textToTranslate);
                        }

                    });

            }
            catch (Exception ex)
            {
                await VS.StatusBar.ShowMessageAsync(ex.Message);
            }
        }

        private string Translate(string textToTranslate, Dictionary<char, char> dict)
        {
            return new string(textToTranslate
                .Select(c =>
                {
                    var tc = char.ToLower(c);
                    var nc = dict.ContainsKey(tc) ? dict[tc] : c;
                    return char.IsLower(c) ? nc : char.ToUpper(nc);
                })
                .ToArray());
        }
    }

}
